package com.zijidelu.luframework.infrastructure.persistence.repository.core.bizsig;

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.zijidelu.luframework.base.bizsig.BizSignature;
import com.zijidelu.luframework.base.bizsig.BizSignatureConditionBuilder;
import com.zijidelu.luframework.base.model.DataModel;
import com.zijidelu.luframework.base.model.PO;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.data.DataRepository;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;

/**
 * 业务签名DTO数据处理实现类。
 *
 * @author ZIJIDELU
 * @datetime 2025/4/18 21:15
 */
@RequiredArgsConstructor
public class BizSigDataProcessorImpl<P extends PO, D extends DataModel> implements BizSigDataProcessor<P, D> {
    private static final int BATCH_SIZE = 1000;
    private final BizSignature<D> bizSignature;

    @Setter(onMethod_ = {@Autowired})
    protected BizSigRepository<P, D> bizSigRepository;
    @Setter(onMethod_ = {@Autowired})
    protected DataRepository<P, D> dataRepository;


    // ==================== 辅助方法 ====================

    /**
     * 根据数据量确定批量处理大小。
     * 小数据量一次性处理，中等数据量使用标准批次，大数据量使用更大批次。
     *
     * @param totalSize 数据量
     * @return 批量处理大小
     */
    protected int determineBatchSize(int totalSize) {
        if (totalSize <= 1000) {
            return totalSize; // 小数据量一次性处理
        } else if (totalSize <= 5000) {
            return 1000; // 中等数据量使用标准批次
        } else {
            return Math.min(2000, totalSize / 5); // 大数据量使用更大批次
        }
    }

    /**
     * 批量处理数据。
     * 每次处理数据量为 {@value BATCH_SIZE} 条。
     *
     * @param dataColl        数据集合
     * @param subListConsumer 子列表数据消费者
     * @param batchSize       每次处理数据量
     */
    protected void batchHandle(Collection<D> dataColl, Consumer<List<D>> subListConsumer, int batchSize) {
        final List<D> dataList = dataColl instanceof ArrayList<D> ? (List<D>) dataColl : new ArrayList<>(dataColl);
        for (int i = 0; i < dataList.size(); i += batchSize) {
            final int end = Math.min(i + batchSize, dataList.size());
            final List<D> dataSubList = dataList.subList(i, end);
            subListConsumer.accept(dataSubList);
        }
    }

    /**
     * 批量处理数据。
     * 每次处理数据量为 {@value BATCH_SIZE} 条。
     *
     * @param dataColl        数据集合
     * @param subListConsumer 子列表数据消费者
     */
    protected void batchHandle(Collection<D> dataColl, Consumer<List<D>> subListConsumer) {
        batchHandle(dataColl, subListConsumer, BATCH_SIZE);
    }

    protected Map<String, D> calcBizSigMap(List<P> poList) {
        if (CollectionUtils.isEmpty(poList)) {
            return Collections.emptyMap();
        }

        return bizSignature.calcBizSignatureDataMap(dataRepository.getDataConverter().poToDataList(poList));
    }


    // ==================== 接口方法实现 (按接口顺序) ====================

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, D> findBatchByQuery(Consumer<QueryChainWrapper<P>> queryConsumer) {
        Objects.requireNonNull(queryConsumer, "queryConsumer must not be null");

        QueryChainWrapper<P> baseQueryChainWrapper = dataRepository.getPersistenceContext().getBaseQueryChainWrapper();
        queryConsumer.accept(baseQueryChainWrapper);

        return calcBizSigMap(baseQueryChainWrapper.list());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, D> findBatchByLambdaQuery(Consumer<LambdaQueryChainWrapper<P>> queryConsumer) {
        Objects.requireNonNull(queryConsumer, "queryConsumer must not be null");

        LambdaQueryChainWrapper<P> baseQueryChainWrapper = dataRepository.getPersistenceContext().getBaseLambdaQueryChainWrapper();
        queryConsumer.accept(baseQueryChainWrapper);

        return calcBizSigMap(baseQueryChainWrapper.list());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, D> findBatch(Collection<D> dataColl) {
        return findBatch(dataColl, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, D> findBatch(Collection<D> dataColl, Consumer<QueryChainWrapper<P>> queryConsumer) {
        if (CollectionUtils.isEmpty(dataColl)) {
            return Collections.emptyMap();
        }

        final Map<String, Collection<Object>> fieldMap = bizSignature.calcFieldNameGroupValues(dataColl);
        // 批量查询所有Data的bizSig数据，BizSigField -> Collection<DataFieldValue>
        return findBatchByQuery(wrapper -> {
                    // 调用者自定义查询条件
                    if (queryConsumer != null) {
                        queryConsumer.accept(wrapper);
                    }
                    // 必须业务签名字段查询，故放在最后防止覆盖
                    fieldMap.forEach(wrapper::in);
                }
        );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, D> findBatchByBuilder(BizSignatureConditionBuilder<D> bizSignatureConditionBuilder) {
        return findBatchByQuery(wrapper -> bizSignatureConditionBuilder.getFieldNameValueMap().forEach(wrapper::in));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, D> findBatchOnlyBizSignature(Collection<D> dataColl) {
        return findBatch(dataColl,
                wrapper -> wrapper.select(true, bizSignature.getBizSignatureFieldNameList())
        );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean exists(final D data) {
        if (Objects.isNull(data)) {
            return false;
        }

        return bizSigRepository.getBizSigPersistenceContext().buildBizSigQueryChain(bizSignature, data).exists();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public D findOne(final D dto) {
        return findOne(dto, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public D findOne(D data, Consumer<LambdaQueryChainWrapper<P>> wrapperConsumer) {
        if (Objects.isNull(data)) {
            return null;
        }

        final LambdaQueryChainWrapper<P> bizSigLambdaQueryChainWrapper = bizSigRepository.getBizSigPersistenceContext()
                .buildBizSigLambdaQueryChain(bizSignature, data);
        if (wrapperConsumer != null) {
            wrapperConsumer.accept(bizSigLambdaQueryChainWrapper);
        }

        return dataRepository.getDataConverter().poToData(bizSigLambdaQueryChainWrapper.one());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean saveOne(final D data) {
        if (Objects.isNull(data)) {
            return true;
        }

        // 唯一键数据已存在
        if (exists(data)) {
            return false;
        }

        return dataRepository.saveOne(data);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean saveBatch(final Collection<D> dataColl) {
        if (CollectionUtils.isEmpty(dataColl)) {
            return true;
        }

        final Map<String, D> bizSigDataMap = findBatchOnlyBizSignature(dataColl);
        for (D data : dataColl) {
            // 唯一键数据已存在，无法插入
            if (bizSigDataMap.containsKey(bizSignature.calcBizSignature(data))) {
                return false;
            }
        }

        return dataRepository.saveBatch(dataColl);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean updateOne(final D data) {
        if (Objects.isNull(data)) {
            return true;
        }

        final D dataByBizSig = findOne(data, wrapper -> wrapper.select(P::getId));

        // 唯一键数据不存在
        if (Objects.isNull(dataByBizSig)) {
            return false;
        }

        data.setId(dataByBizSig.getId());

        return dataRepository.updateById(data);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean updateBatch(final Collection<D> dataColl) {
        if (CollectionUtils.isEmpty(dataColl)) {
            return true;
        }

        final List<String> bizSigFieldList = new ArrayList<>(bizSignature.getBizSignatureFieldNameList());
        bizSigFieldList.add("id");

        // 分批处理
        final Map<String, D> bizSigDataMap = new HashMap<>(dataColl.size());
        batchHandle(
                dataColl,
                subList -> bizSigDataMap.putAll(findBatch(subList, wrapper -> wrapper.select(bizSigFieldList))),
                determineBatchSize(dataColl.size())
        );

        for (D data : dataColl) {
            final String bizSig = bizSignature.calcBizSignature(data);
            // 记录不存在无法更新
            if (!bizSigDataMap.containsKey(bizSig)) {
                return false;
            }
            // 设置ID
            data.setId(bizSigDataMap.get(bizSig).getId());
        }

        return dataRepository.updateBatchById(dataColl);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean deleteOne(final D data) {
        if (Objects.isNull(data)) {
            return true;
        }

        return bizSigRepository.getBizSigPersistenceContext().buildBizSigLambdaUpdateChain(bizSignature, data).remove();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean deleteBatch(final Collection<D> dataColl) {
        if (CollectionUtils.isEmpty(dataColl)) {
            return true;
        }

        final List<String> bizSigFieldList = new ArrayList<>(bizSignature.getBizSignatureFieldNameList());
        bizSigFieldList.add("id");

        // 业务签名数据映射
        final Map<String, D> bizSigDataMap = new HashMap<>(dataColl.size());
        // 分批处理
        batchHandle(dataColl, subList -> bizSigDataMap.putAll(findBatch(subList, wrapper ->
                wrapper.select(bizSigFieldList))
        ));

        final Set<Serializable> idSet = new HashSet<>();
        for (D data : dataColl) {
            final String bizSig = bizSignature.calcBizSignature(data);
            if (bizSigDataMap.containsKey(bizSig)) {
                // 设置ID
                idSet.add(bizSigDataMap.get(bizSig).getId());
            }
        }

        return dataRepository.deleteBatchById(idSet);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean saveOrUpdateBatch(final Collection<D> dataColl) {
        if (CollectionUtils.isEmpty(dataColl)) {
            return true;
        }

        final List<String> bizSigFieldList = new ArrayList<>(bizSignature.getBizSignatureFieldNameList());
        // 添加ID字段，用于更新
        bizSigFieldList.add("id");

        // 分批处理
        final Map<String, D> bizSigDataMap = new HashMap<>(dataColl.size());
        // 查询所有Data的bizSig数据
        batchHandle(
                dataColl,
                subList -> bizSigDataMap.putAll(findBatch(subList, wrapper -> wrapper.select(bizSigFieldList))),
                determineBatchSize(dataColl.size())
        );

        for (D data : dataColl) {
            final String bizSig = bizSignature.calcBizSignature(data);
            // 存在则更新，不存在则新增
            if (bizSigDataMap.containsKey(bizSig)) {
                // 存在则更新
                // 设置ID
                data.setId(bizSigDataMap.get(bizSig).getId());
            } else {
                // 新增
                data.setId(null);
            }
        }

        return dataRepository.saveOrUpdateBatch(dataColl);
    }
}
